package com.zjp.mg.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.github.javafaker.Faker;
import com.mongodb.bulk.BulkWriteResult;
import com.mongodb.client.result.UpdateResult;
import com.zjp.mg.core.UpdateCondition;
import com.zjp.mg.dao.AbstractMongoService;
import com.zjp.mg.model.User;
import com.zjp.mg.model.UserQuery;
import org.bson.json.JsonMode;
import org.bson.json.JsonWriterSettings;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.mapping.MongoId;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

@Service
public class UserMgService extends AbstractMongoService<User> {

    @Override
    public String getCollectionName() {
        return "user";
    }

    @Override
    public Class<User> getType() {
        return User.class;
    }

    public User insertByNextAutoId(User object) {
        object.setUserId(getNextAutoId());
        return insert(object);
    }


    public List<User> findNameList(String name) {
        return find(new Query(Criteria.where("username").is(name)));
    }


    public Query initPageQuery(UserQuery userQuery) {
        Query query = new Query();
        String username = userQuery.getUsername();
        if (StrUtil.isNotEmpty(username)) {
            String regexStr = String.format(".*%s.*", username);
            Criteria c1 = Criteria.where("username").regex(regexStr);
            query.addCriteria(c1);
        }
        Integer age = userQuery.getAge();
        if (Objects.nonNull(age)) {
            Criteria c2 = Criteria.where("age").is(age);
            query.addCriteria(c2);
        }


        query.with(Sort.by(Sort.Direction.DESC, "_id"));
        return query;
    }

    public UpdateResult updateById(User user) {
        return updateFirst(new Query(Criteria.where("_id").is(user.getUserId())),
                new Update()
                        .set("username", user.getUsername())
                        .set("school", user.getSchool())
                        .set("age", user.getAge())
                        .set("time", user.getTime())
                        .set("city", user.getCity()));
    }

    public static void initModifierOps(User user) throws IllegalAccessException {
        Class<? extends User> userClass = user.getClass();
        Field[] fields = userClass.getDeclaredFields();
        Query query = new Query();
        Update update = new Update();
        for (Field field : fields) {
            if (Modifier.isFinal(field.getModifiers())) {
                continue;
            }
            System.out.println(field.getName());
            // 强制访问
            field.setAccessible(true);
            MongoId annotation = field.getAnnotation(MongoId.class);
            if (Objects.nonNull(annotation)) {
                query.addCriteria(Criteria.where("_id").is(field.get(user)));
            } else {
                update.set(field.getName(), field.get(user));
            }
        }
        System.out.println(query.getQueryObject().toJson(JsonWriterSettings.builder().outputMode(JsonMode.SHELL).build()));

        System.out.println(update.getUpdateObject().toJson(JsonWriterSettings.builder().outputMode(JsonMode.STRICT).build()));
        System.out.println(update.getUpdateObject().toJson(JsonWriterSettings.builder().outputMode(JsonMode.SHELL).build()));
        System.out.println(update.getUpdateObject().toJson(JsonWriterSettings.builder().outputMode(JsonMode.EXTENDED).build()));
        System.out.println(update.getUpdateObject().toJson(JsonWriterSettings.builder().outputMode(JsonMode.RELAXED).build()));
    }

    public static void main(String[] args) {

        Faker faker = Faker.instance(Locale.CHINA);
        User user = new User(faker.name().name(),
                faker.university().name(), RandomUtil.randomInt(90),
                DateUtil.offsetMillisecond(DateUtil.date(), RandomUtil.randomInt()).toJdkDate());
        int randomInt = RandomUtil.randomInt(1, 6);
        List<String> cityList = new ArrayList<>();
        for (int j = 0; j < randomInt; j++) {
            cityList.add(faker.address().city());
        }
        user.setCity(cityList);

        try {
            initModifierOps(user);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }


    /**
     * 用于按顺序添加多个单个操作或类似操作列表，最终可以通过调用execute()来执行
     */

    public void batchUpdate() {
        List<User> all = findAll();
        Faker faker = Faker.instance(Locale.CHINA);
        BulkOperations bulkOperations = bulkOps(BulkOperations.BulkMode.UNORDERED);
        for (User user : all) {
            user.setUsername(faker.name().name());
            user.setSchool(faker.university().name());
            UpdateCondition updateCondition = initUpdateCondition(user);
            bulkOperations.updateOne(updateCondition.getQuery(), updateCondition.getUpdate());
        }
        BulkWriteResult execute = bulkOperations.execute();
        int modifiedCount = execute.getModifiedCount();


        Assert.isTrue(modifiedCount == all.size(), "修改数量异常");

    }

}
